package org.aeon.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.aeon.client.context.GlobalContext;
import org.aeon.client.handler.Inbound.*;
import org.aeon.client.handler.outbound.MessageTokenHandler;
import org.aeon.config.Config;
import org.aeon.message.PingMessage;
import org.aeon.protocol.MessageCodecSharable;
import org.aeon.protocol.ProtocolFrameDecoder;

import java.net.InetSocketAddress;

/**
 * @author: MissingAeon
 * @date: 2024/1/25 13:12
 * @description:
 */
@Slf4j
public class ChatClient {
    private final Bootstrap bootstrap;
    private final NioEventLoopGroup GROUP;

    public ChatClient() {
        log.debug("客户端正在启动...");
        bootstrap = new Bootstrap();
        GROUP = new NioEventLoopGroup();
        init();
    }

    private void init() {
        final LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        final MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        final LoginResponseHandler LOGIN_HANDLER = new LoginResponseHandler();
        final ChatResponseHandler CHAT_HANDLER = new ChatResponseHandler();
        final GroupChatResponseHandler GROUP_CHAT_HANDLER = new GroupChatResponseHandler();
        final ClientChannelInboundHandler CLIENT_CHANNEL_HANDLER = new ClientChannelInboundHandler();
        final MessageTokenHandler TOKEN_HANDLER = new MessageTokenHandler();
        final RegisterResponseHandler REGISTRATION_HANDLER = new RegisterResponseHandler();
        final FriendApplyResponseHandler FRIEND_APPLY_HANDLER = new FriendApplyResponseHandler();
        final FriendApplyListResponseHandler FRIEND_APPLY_LIST_HANDLER = new FriendApplyListResponseHandler();
        final FriendAddResponseHandler FRIEND_ADD_HANDLER = new FriendAddResponseHandler();
        final RequestLoginResponseHandler REQUEST_LOGIN_HANDLER = new RequestLoginResponseHandler();
        final FriendDeleteResponseHandler FRIEND_DELETE_HANDLER = new FriendDeleteResponseHandler();
        final BlacklistModifyResponseHandler BLACK_MODIFY_HANDLER = new BlacklistModifyResponseHandler();
        final ListQueryResponseHandler LIST_QUERY_HANDLER = new ListQueryResponseHandler();
        final GroupsListResponseHandler GROUPS_LIST_HANDLER = new GroupsListResponseHandler();
        final SearchResponseHandler SEARCH_HANDLER = new SearchResponseHandler();
        final UserInfoResponseHandler USER_INFO_HANDLER = new UserInfoResponseHandler();
        final GroupInfoResponseHandler GROUP_INFO_HANDLER = new GroupInfoResponseHandler();
        final GroupQuitResponseHandler GROUP_QUIT_HANDLER = new GroupQuitResponseHandler();
        final GroupCreateResponseHandler GROUP_CREATE_HANDLER = new GroupCreateResponseHandler();
        final ResponseHandler RESPONSE_HANDLER = new ResponseHandler();

        try {
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(GROUP);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ProtocolFrameDecoder());
                    // ch.pipeline().addLast(LOGGING_HANDLER);
                    ch.pipeline().addLast(MESSAGE_CODEC);
                    // 心跳检测
                    ch.pipeline().addLast(new IdleStateHandler(0, 7, 0));
                    ch.pipeline().addLast(new ChannelDuplexHandler() {
                        // 特殊事件触发
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                            final IdleStateEvent event = (IdleStateEvent) evt;
                            // 判断是否触发读空闲事件
                            if (event.state() == IdleState.WRITER_IDLE) {
                                ctx.writeAndFlush(new PingMessage());
                            }
                        }
                    });
                    // 业务
                    ch.pipeline().addLast(TOKEN_HANDLER);
                    ch.pipeline().addLast(CLIENT_CHANNEL_HANDLER);
                    ch.pipeline().addLast(LOGIN_HANDLER);
                    ch.pipeline().addLast(REGISTRATION_HANDLER);
                    ch.pipeline().addLast(REQUEST_LOGIN_HANDLER);
                    ch.pipeline().addLast(FRIEND_APPLY_HANDLER);
                    ch.pipeline().addLast(FRIEND_APPLY_LIST_HANDLER);
                    ch.pipeline().addLast(FRIEND_ADD_HANDLER);
                    ch.pipeline().addLast(FRIEND_DELETE_HANDLER);
                    ch.pipeline().addLast(BLACK_MODIFY_HANDLER);
                    ch.pipeline().addLast(LIST_QUERY_HANDLER);
                    ch.pipeline().addLast(GROUPS_LIST_HANDLER);
                    ch.pipeline().addLast(GROUP_CHAT_HANDLER);
                    ch.pipeline().addLast(CHAT_HANDLER);
                    ch.pipeline().addLast(SEARCH_HANDLER);
                    ch.pipeline().addLast(USER_INFO_HANDLER);
                    ch.pipeline().addLast(GROUP_INFO_HANDLER);
                    ch.pipeline().addLast(GROUP_QUIT_HANDLER);
                    ch.pipeline().addLast(GROUP_CREATE_HANDLER);
                    ch.pipeline().addLast(RESPONSE_HANDLER);
                }
            });
        } catch (Exception e) {
            GROUP.shutdownGracefully();
            log.debug("客户端关闭完成...");
        }
    }

    public void startUp() {
        try {
            final Channel channel = bootstrap.connect(new InetSocketAddress(Config.getServerHost(), Config.getServerPort())).sync().channel();
            GlobalContext.getContext().setChannel(channel);
            log.debug("客户端启动完毕...");
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
        } finally {
            GROUP.shutdownGracefully();
            GlobalContext.getContext().setChannel(null);
        }
    }
}
